package top.xzxsrq.web.download;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import top.xzxsrq.common.utils.FileUtilsZX;
import top.xzxsrq.common.utils.Platform;
import top.xzxsrq.web.download.entity.PageInfo;
import top.xzxsrq.web.utils.WebUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Consumer;

/**
 * 下载的线程池
 */
@Data
@Log4j2
public class DownloadThread implements Callable<Void> {
    private static final ScheduledExecutorService threadPoolExecutor = Executors.newScheduledThreadPool(DownloadManager.THREAD_NUMBER + 1);

    protected PageInfo pageInfo;
    protected String savePath;
    protected String downloadType;
    protected Process process;
    protected String downloadId;
    private List<Consumer<Void>> finishedCall = new LinkedList<>();
    private Future<Void> voidFuture; // 存一下线程池提交返回来的future
    private final String downloadSelfId = WebUtils.uuid64(); // 自己的id
    private final long startTime = System.currentTimeMillis(); // 创建的开始时间

    public void setFinishedCall(List<Consumer<Void>> finishedCall) {
    }

    public Consumer<Void> addFinishedCall(Consumer<Void> add) {
        this.finishedCall.add(add);
        return add;
    }

    @Override
    public Void call() {
        if (this.isCanStop()) {
            log.info("任务id：{}：任务类型：{},线程正常退出：线程id：{}",downloadId,downloadType,downloadSelfId);
            DownloadManager.remove(this);
            return null;
        }
        try {
            overCall();
        } catch (Exception e) {
            log.info("任务id：{}：任务类型：{},下载任务发生错误：{}",downloadId,downloadType,e.getMessage());
        }
        log.info("任务id：{}：任务类型：{},线程正常退出：线程id：{}",downloadId,downloadType,downloadSelfId);
        DownloadManager.remove(this);
        for (Consumer<Void> voidConsumer : finishedCall) {
            voidConsumer.accept(null);
        }
        return null;
    }

    public void overCall() throws IOException, InterruptedException {
        downloadFunc();
    }

    private String getDownloadingPath() {
        return savePath + downloadId + ".downloading";
    }

    public void downloadFunc() throws IOException, InterruptedException {
        if (this.isCanStop()) {
            this.destroy();
            return;
        }
        FileUtilsZX.createFile(getDownloadingPath());
        createProcess();
        BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(), setProcessOutStrCharsetName()));
        String line;
        while ((line = br.readLine()) != null) {
            if (this.isCanStop()) {
                process.destroyForcibly();
                this.destroy();
                return;
            }
            showProcessLog(line);
        }
        if (pageInfo.getDownloadPer() > 99) {
            pageInfo.setDownloadPer(100f);
        }
        process.waitFor();
        process.destroy();
        FileUtilsZX.deleteFile(getDownloadingPath());
    }

    /**
     * 设置获取子进程控制台的编码
     */
    protected String setProcessOutStrCharsetName() {
        if (Platform.isWindows()) {
            return "GBK";
        }
        return "UTF-8";
    }

    /**
     * 创建进程一定要重写
     */
    protected void createProcess() {
    }

    /**
     * 显示进程信息，进度重写，VideoDT就重写读取信息写入进度
     *
     * @param line
     */
    protected void showProcessLog(String line) {
    }

    public JSONObject getDownloadInfo() {
        return JSON.parseObject(JSON.toJSONString(this));
    }

    /**
     * 不采用中断的形式，而是让线程正常完成和退出
     */
    private volatile boolean stopThisThread = false;

    protected final boolean isCanStop() {
        return stopThisThread || Thread.currentThread().isInterrupted();
    }

    /**
     * 取消线程
     */
    public synchronized void cancel() {
        stopThisThread = true;
        if(voidFuture != null) {
            voidFuture.cancel(true);
        }
        this.destroy();
    }

    protected void destroy() {
        stopThisThread = true;
        log.info("取消任务：任务id：{}：任务类型：{}", downloadId, downloadType);
        if (process == null) {
            log.info("取消任务：任务id：{}：任务类型：{}：强行销毁子进程：没有子进程", downloadId, downloadType);
        } else if (!process.isAlive()) {
            log.info("取消任务：任务id：{}：任务类型：{}：强行销毁子进程：子进程已关闭", downloadId, downloadType);
        } else {
            log.info("取消任务：任务id：{}：任务类型：{}：强行销毁子进程", downloadId, downloadType);
            process.destroyForcibly();
        }
        if (pageInfo == null) {
            if (savePath != null) {
                log.info("取消任务：任务id：{}：任务类型：{}：删除保存的文件：{}", downloadId, downloadType, savePath);
                FileUtilsZX.deleteFile(savePath);
            }
        } else {
            if (pageInfo.getDownloadPer() < 100) {
                if (savePath != null) {
                    log.info("取消任务：任务id：{}：任务类型：{}：删除保存的文件：{}", downloadId, downloadType, savePath);
                    FileUtilsZX.deleteFile(savePath);
                }
            }
        }
        if (savePath != null) {
            log.info("取消任务：任务id：{}：任务类型：{}：删除loading标识文件：{}", downloadId, downloadType, getDownloadingPath());
            FileUtilsZX.deleteFile(getDownloadingPath());
        }
        destroyFunChildrenOver();
        log.info("取消任务完成：任务id：{}：任务类型：{}", downloadId, downloadType);
    }

    /**
     * 用于取消任务子项的重写
     */
    protected void destroyFunChildrenOver() {}
}
